package com.cw.utils.web;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.regex.Matcher;

/*
 * @Author 陈伟
 * @Date 2021/3/8 17:34
 * @description xss过滤，不使用正则匹配（效率很低），目前使用系统有sso、mer、bpm、mobile
 * @param: null
 * @Return
 */
public class XssCommonUtils {
    private static Logger logger = LoggerFactory.getLogger(XssCommonUtils.class);
    private static String[] xssArray = new String[100];
    private static String[] fwbXssArray = new String[100];
    private static String[] xssOtherArray = new String[20];

    public static final String xss_sso = "sso";
    public static final String xss_mer = "mer";
    public static final String xss_bpm = "bpm";
    public static final String xss_mp = "mp";


    /*
     * @Author 陈伟
     * @Date 2021/3/8 17:40
     * @description
     * @param: type 可以根据不同系统，设置不同参数.
     * @Return java.lang.String[]
     */
    private static String[] getXssPatternArray(String type) {
        if(xssArray == null || xssArray[0] == null){
            //默认设置。共81个
            String xssStr = "<script>|</script>|oncontrolselect|oncopy=|oncut=|ondataavailable|ondatasetchanged|ondatasetcomplete|ondblclick|" +
                    "ondeactivate|ondrag|ondragend|ondragenter|ondragleave|ondragover|ondragstart|ondrop|onerror=|onerror |onerror+|onerror%20|onerroupdate|onfilterchange|" +
                    "onfinish|onfocus|onfocusin|onfocusout|onhelp|onkeydown|onkeypress|onkeyup|onlayoutcomplete|onload|onlosecapture|" +
                    "onmousedown|onmouseenter|onmouseleave|onmousemove|onmousout|onmouseover|onmouseup|onmousewheel|onmove|onmoveend|" +
                    "onmovestart|onabort|onactivate|onafterprint|onafterupdate|onbefore|onbeforeactivate|onbeforecopy|onbeforecut|" +
                    "onbeforedeactivate|onbeforeeditocus|onbeforepaste|onbeforeprint|onbeforeunload|onbeforeupdate|onblur|onbounce|" +
                    "oncellchange|onchange|onclick|oncontextmenu|onpaste|onpropertychange|onreadystatechange|onreset|onresize|onresizend|" +
                    "onresizestart|onrowenter|onrowexit|onrowsdelete|onrowsinserted|onscroll|onselect|onselectionchange|onselectstart|onstart|" +
                    "onstop|onsubmit|onunload|ontoggle|onwheel|oninput|javascript|onmouseout|:prompt|onerror%3D|src%3D|alert%28|script%3e|confirm=|%3Cimg";
            if(xss_sso.equals(type)){

            }else if(xss_mer.equals(type)){
                xssStr+="href=|<img|src=|alert(|<input";
            }else if(xss_bpm.equals(type)){
                xssStr+="href=|<img|src=|alert(|<input";
            }else if(xss_mp.equals(type)){

            }
            xssArray = xssStr.split("\\|");
        }
        return xssArray;
    }


    private static String[] getFwbXssPatternArray() {
        if(fwbXssArray == null || fwbXssArray[0] == null){
            //默认设置。共81个
            String xssStr = "<script>|</script>|oncontrolselect|oncopy|oncut|ondataavailable|ondatasetchanged|ondatasetcomplete|ondblclick|" +
                    "ondeactivate|ondrag|ondragend|ondragenter|ondragleave|ondragover|ondragstart|ondrop|onerror=|onerror |onerror+|onerror%20|onerroupdate|onfilterchange|" +
                    "onfinish|onfocus|onfocusin|onfocusout|onhelp|onkeydown|onkeypress|onkeyup|onlayoutcomplete|onload|onlosecapture|" +
                    "onmousedown|onmouseenter|onmouseleave|onmousemove|onmousout|onmouseover|onmouseup|onmousewheel|onmove|onmoveend|" +
                    "onmovestart|onabort|onactivate|onafterprint|onafterupdate|onbefore|onbeforeactivate|onbeforecopy|onbeforecut|" +
                    "onbeforedeactivate|onbeforeeditocus|onbeforepaste|onbeforeprint|onbeforeunload|onbeforeupdate|onblur|onbounce|" +
                    "oncellchange|onchange|onclick|oncontextmenu|onpaste|onpropertychange|onreadystatechange|onreset|onresize|onresizend|" +
                    "onresizestart|onrowenter|onrowexit|onrowsdelete|onrowsinserted|onscroll|onselect|onselectionchange|onselectstart|onstart|" +
                    "onstop|onsubmit|onunload|ontoggle|onwheel|oninput|javascript|";
            fwbXssArray = xssStr.split("\\|");
        }
        return fwbXssArray;
    }

//    private static String[] getXssOtherPatternArray(String type) {
//        if(xssOtherArray == null || xssOtherArray[0] == null){
//            //默认设置。共81个
//            String xssStr = "";
//            if(xss_sso.equals(type)){
//
//            }else if(xss_mer.equals(type)){
//                xssStr+="href=|<img|src=|alert(|<input";
//            }else if(xss_bpm.equals(type)){
//                xssStr+="href=|<img|src=|alert(|<input";
//            }else if(xss_mp.equals(type)){
//
//            }
//            xssOtherArray = xssStr.split("\\|");
//        }
//        return xssOtherArray;
//    }

    /*
     * @Author 陈伟
     * @Date 2021/3/19 15:31
     * @description 请求参数xss处理
     * @param: value
     * @Return java.lang.String
     */
    public static String stripXss(String value, String type) {
        if(StringUtils.isNotBlank(value)) {
            for(String xss : getXssPatternArray(type)) {
                if(value.toLowerCase().contains(xss.toLowerCase())){
                    logger.warn("富文本XSS攻击进行xss过滤清除===>修改前参数值为:{}",value);
                    // 忽略大小写匹配，删除攻击脚本
                    value = value.replaceAll("(?i)"+xss,"");
                    logger.warn("富文本XSS攻击进行xss过滤清除===>修改后参数值为:{}",value);
                }
            }
            if (value.contains("<")){
                logger.warn("普通参数XSS攻击进行xss过滤转义===>修改前参数值为:{}",value);
                // 转义相关字符串
                value = value.replaceAll("<", "&lt;");
                logger.warn("普通参数XSS攻击进行xss过滤转义===>修改后参数值为:{}",value);
            }

        }
        return value;
    }

    /*
     * @Author 陈伟
     * @Date 2021/5/24 14:38
     * @description 转义相关字符串
     * @param: value
     * @Return java.lang.String
     */
    public static String stripXssFormat(String value) {
        if(StringUtils.isNotBlank(value)) {
            if (value.contains("<")) {
                logger.warn("普通参数XSS攻击进行xss过滤转义===>修改前参数值为:{}", value);
                // 转义相关字符串
                value = value.replaceAll("<", "&lt;");
                logger.warn("普通参数XSS攻击进行xss过滤转义===>修改后参数值为:{}", value);
            }
        }
        return value;
    }

//    public static boolean stripXssBoolean(String value) {
//        boolean flag = true;
//        if(StringUtils.isNotBlank(value)) {
//            for(String xss : getXssPatternArray("")) {
//                if(value.toLowerCase().contains(xss.toLowerCase())){
//                    flag = false;
//                    break ;
//                }
//            }
//        }
//        return flag;
//    }

    public static boolean stripXssOtherBoolean(String value, String type) {
        boolean flag = true;
        if(StringUtils.isNotBlank(value)) {
            for(String xss : getXssPatternArray(type)) {
                if(value.toLowerCase().contains(xss.toLowerCase())){
                    logger.warn("存在XSS攻击敏感词===>字符为:{}",xss);
                    flag = false;
                    break ;
                }
            }
        }
        return flag;
    }

    /*
     * @Author 陈伟
     * @Date 2021/5/24 14:32
     * @description 递归循环重复替换。（应对情况:onconclicklick）
     * @param: value
     * @Return java.lang.String
     */
    private static String recursionXssString(String value){
        boolean flag = true;
        for(String xss : getXssPatternArray("")) {
            if(value.toLowerCase().contains(xss.toLowerCase())){
                flag = false;
                logger.warn("富文本XSS攻击进行xss过滤清除===>修改前参数值为:{}",value);
                // 忽略大小写匹配，删除攻击脚本
                value = value.replaceAll("(?i)"+xss,"");
                logger.warn("富文本XSS攻击进行xss过滤清除===>修改后参数值为:{}",value);
            }
        }
        if(flag){
            return value;
        }
        return recursionXssString(value);
    }

    /**
     *  富文本处理
     */
    public static String stripXssByUeditor(String value) {
        if(StringUtils.isNotBlank(value)) {
            Matcher matcher = null;
            for(String xss : getFwbXssPatternArray()) {
                if(value.toLowerCase().contains(xss.toLowerCase())){
                    logger.warn("富文本XSS攻击进行xss过滤清除===>修改前参数值为:{}",value);
                    // 忽略大小写匹配，删除攻击脚本
                    value = value.replaceAll("(?i)"+xss,"");
                    logger.warn("富文本XSS攻击进行xss过滤清除===>修改后参数值为:{}",value);
                }
            }
        }
        return value;
    }

//        /*过滤策略：把特殊字符转为HTML实体编码，
//         *这样存在数据库里较安全
//         *返回给前端时会被js解析为正常字符，不影响查看*/
//        public static String xssEncode(String str){
//            if(str == null || str.isEmpty()){
//                return str;
//            }
//            str = str.replaceAll(";", "&#59;");
//            str = str.replaceAll("<", "&#60;").replaceAll(">", "&#62;");
//            str = str.replaceAll("\\(", "&#40;").replaceAll("\\)", "&#41;");
//            str = str.replaceAll("'", "&#39;").replaceAll("\"", "&#34;");
//            str = str.replaceAll("\\$", "&#36;");
//            str = str.replaceAll("%", "&#37;");
//            str = str.replaceAll("\\/", "&#47;").replaceAll("\\\\", "&#92;");
//            str = str.replaceAll(":", "&#58;");
//            str = str.replaceAll("\\?", "&#63;").replaceAll("@", "&#64;");
//            str = str.replaceAll("\\^", "&#94;");
//            return str;
//        }


//    public static void main(String[] args) {
//        String value = null;
//       Long start = new Date().getTime();
//        for (int i = 0; i < 5; i++) {
//            //value = XssCommonUtils.stripXss("https://hxsso.mp.hxb.com.cn/userLogin/forgetPWDInit.do?userName=%22onmOuseOvEr=prompt(s1)//&service=https://hxyh.bpm.hxb.com.cn:443/userLogin/ssoRedirect.do?service=https://hxyh.bpm.hxb.com.cn:443/userLogin/index.do");
//            //value = XssCommonUtils.stripXss("<");
//            //value = XssCommonUtils.stripXss("<script>q123123\"12312\"</script>");
//            value = XssCommonUtils.stripXss("{\"id\":\"123\"},https://aaaaa/cccc?aa=11&bb='22l'&alert(11)");
//            System.out.println("type-s1: '" + value + "'");
//        }
//        Long end  = new Date().getTime();
//        System.out.println("用时===="+(end-start));
//    }
}
